package com.erlin.common.handler;

import com.erlin.common.exception.ElException;
import com.erlin.common.exception.ElParamException;
import com.erlin.common.vo.ResponseVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.ResponseEntity;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Errors;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 异常的全局处理
 *
 * @author Sola
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
    private final Integer INTERNAL_SERVER_ERROR = 500;

    /**
     * 处理通用业务异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(ElException.class)
    public ResponseVo<?> resolveSmsException(ElException e) {
        log.error(e.getMessage(), e);
        return ResponseVo.exception(e.getMessage());
    }

    /**
     * 处理参数异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(ElParamException.class)
    public ResponseVo<?> resolveParamException(ElParamException e) {
        log.error(e.getMessage(), e);
        return ResponseVo.exception(e.getMessage());
    }

    /**
     * 用来处理bean validation异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public ResponseVo<?> resolveMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        // 获取错误信息
        List<String> bindErrorMsgs = getBindErrorMsg(e.getBindingResult());
        String errorMsg = CollectionUtils.isEmpty(bindErrorMsgs) ? e.getMessage() : bindErrorMsgs.get(0);
        log.error(errorMsg, e);
        return ResponseVo.exception(errorMsg);
    }
    /**
     * 处理其他异常, 特殊处理, 将response status code设为500
     *
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class)
    public ResponseEntity<?> resolveException(Exception e) {
        log.error("未知异常, msg: " + e.getMessage(), e);
        ResponseVo<?> body = ResponseVo.exception(e.getMessage());
        return ResponseEntity.status(INTERNAL_SERVER_ERROR).body(body);
    }

    /**
     * 从BindingResult中获取默认错误信息集合
     *
     * @param
     * @return
     */
    private List<String> getBindErrorMsg(BindingResult result) {
        return Optional.ofNullable(result)
                .map(Errors::getFieldErrors).orElse(Collections.emptyList()).stream()
                .map(DefaultMessageSourceResolvable::getDefaultMessage)
                .collect(Collectors.toList());

    }
}
